#include "FLOAT.h"

FLOAT F_mul_F(FLOAT a, FLOAT b) {
	long long product_64bit = 1ll * a * b;
	return (FLOAT)(product_64bit >> 16);
}

FLOAT F_div_F(FLOAT a, FLOAT b) {
	/* Dividing two 64-bit integers needs the support of another library
	 * `libgcc', other than newlib. It is a dirty work to port `libgcc'
	 * to NEMU. In fact, it is unnecessary to perform a "64/64" division
	 * here. A "64/32" division is enough.
	 *
	 * To perform a "64/32" division, you can use the x86 instruction
	 * `div' or `idiv' by inline assembly. We provide a template for you
	 * to prevent you from uncessary details.
	 *
	 *     asm volatile ("??? %2" : "=a"(???), "=d"(???) : "r"(???), "a"(???), "d"(???));
	 *
	 * If you want to use the template above, you should fill the "???"
	 * correctly. For more information, please read the i386 manual for
	 * division instructions, and search the Internet about "inline assembly".
	 * It is OK not to use the template above, but you should figure
	 * out another way to perform the division.
	 */
	int sign_factor = 1;
	if ((a < 0) == 1) sign_factor *= -1,a = -a;
	if ((b < 0) == 1) sign_factor *= -1,b = -b;

	int result = a / b;
	a %= b;

	int bit_index;
	for (bit_index = 0;bit_index < 16;bit_index++){
		a <<= 1;
		result <<= 1;
		if (a >= b) a -= b, result |= 1;
	}
	return sign_factor * result; 

	
}

FLOAT f2F(float a) {
	/* You should figure out how to convert `a' into FLOAT without
	 * introducing x87 floating point instructions. Else you can
	 * not run this code in NEMU before implementing x87 floating
	 * point instructions, which is contrary to our expectation.
	 *
	 * Hint: The bit representation of `a' is already on the
	 * stack. How do you retrieve it to another variable without
	 * performing arithmetic operations on it directly?
	 */

	int float_bits = *(int *)&a;
	int sign = float_bits & 0x80000000;
	int exponent = (float_bits >> 23) & 0xff;
	int mantissa = float_bits & 0x7fffff;	
	
	if(exponent == 255) {
		if (sign) return -0x7fffffff;
		else return 0x7fffffff;
	}
	
	if(exponent == 0) return 0;

	mantissa |= 1 << 23;
	exponent -= 134;	
	if (exponent < 0) mantissa >>= -exponent;
	if (exponent > 0) mantissa <<= exponent;

	if (sign) return -mantissa;else return mantissa;
}

FLOAT Fabs(FLOAT a) {
	if (a < 0) return -a;else return a;
}

/* Functions below are already implemented */

FLOAT sqrt(FLOAT x) {
	FLOAT delta, estimate = int2F(2);

	do {
		delta = F_div_int((F_div_F(x, estimate) - estimate), 2);
		estimate += delta;
	} while(Fabs(delta) > f2F(1e-4));

	return estimate;
}

FLOAT pow(FLOAT x, FLOAT y) {
	/* we only compute x^0.333 */
	FLOAT square, delta, estimate = int2F(2);

	do {
		square = F_mul_F(estimate, estimate);
		delta = (F_div_F(x, square) - estimate) / 3;
		estimate += delta;
	} while(Fabs(delta) > f2F(1e-4));

	return estimate;
}

